package com.xinlianshiye.im.service.impl;

import com.xinlianshiye.im.RequestEnum;
import com.xinlianshiye.im.bean.App;
import com.xinlianshiye.im.dao.FriendApplicationDao;
import com.xinlianshiye.im.dao.FriendDao;
import com.xinlianshiye.im.dao.RecordDao;
import com.xinlianshiye.im.dao.UserDao;
import com.xinlianshiye.im.response.UserRecordlist;
import com.xinlianshiye.im.bean.User;
import com.xinlianshiye.im.bean.UserGroup;
import com.xinlianshiye.im.response.*;
import com.xinlianshiye.im.service.*;
import com.xinlianshiye.im.utils.AuthUtil;
import com.xinlianshiye.im.utils.RedisReceiver;
import com.xinlianshiye.im.Result;
import com.xinlianshiye.im.utils.SessionManager;
import com.xinlianshiye.clouds.common.exception.WebMessageExceptionBuilder;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.websocket.Session;
import java.util.ArrayList;
import java.util.List;

@DubboService(version = "1.0")
@Service
@Transactional(rollbackFor = {Exception.class})
public class UserServiceImpl implements UserService {

    public UserServiceImpl(UserDao userDao, FriendDao friendDao, RecordDao recordDao, FriendApplicationDao friendApplicationDao, WebMessageExceptionBuilder exceptionBuilder, AuthUtil authUtil) {
        this.userDao = userDao;
        this.friendDao = friendDao;
        this.recordDao = recordDao;
        this.friendApplicationDao = friendApplicationDao;
        this.exceptionBuilder = exceptionBuilder;
        this.authUtil = authUtil;
    }

    private final UserDao userDao;
    private final FriendDao friendDao;
    private final RecordDao recordDao;
    private final FriendApplicationDao friendApplicationDao;
    private final WebMessageExceptionBuilder exceptionBuilder;
    private final AuthUtil authUtil;

    @Autowired
    private AppService appService;
    @Autowired
    private RedisReceiver redisReceiver;
    @Autowired
    private SessionManager sessionManager;
    @Autowired
    private RecordService recordService;
    @Value("${defaultIcon}")
    private String icon;
    @Autowired
    private OriginUserService originUserService;
    @Autowired
    private UserGroupService userGroupService;

    @Override
    public void sendInit(Integer userId) {
        User user = getOrElseThrow(userId);
        InitViews iv = new InitViews();
        //个人信息
        iv.setId(user.getId());
        iv.setUsername(user.getUsername());
        iv.setAvatar(user.getAvatar());
        iv.setSign(user.getSign());
        Integer applyNum = friendApplicationDao.countApplyMsg(userId);
        iv.setRecordNum(recordDao.countByOwnerIdAndHaveReadAndIsSender(userId, false, false));
        iv.setChaeckNum(applyNum + recordDao.countByOwnerIdAndHaveReadAndIsSender(userId, false, false));
        iv.setApplyNum(applyNum);
        iv.setStatus(sessionManager.isUserOnline(user.getId()) ? User.OnlineStateEnum.ONLINE.ordinal() : User.OnlineStateEnum.OFFLINE.ordinal());
        //friend分组信息
        List<UserGroup> userGroups = userGroupService.list(user.getId());
        List<GroupfriendsList> groupfriendsLists = new ArrayList<>();
        userGroups.forEach(group -> {
            GroupfriendsList gf = new GroupfriendsList();
            gf.setId(group.getId());
            gf.setName(group.getName());
            List<User> users = friendDao.listGroupId(group.getId());
            List<UserInfo> userList = new ArrayList<>();
            users.forEach(us -> {
                UserInfo ur = new UserInfo();
                ur.setId(us.getId());
                ur.setUsername(us.getUsername());
                ur.setAvatar(us.getAvatar());
                ur.setSign(us.getSign());
                userList.add(ur);
            });
            gf.setList(userList);
            groupfriendsLists.add(gf);
        });
        iv.setList(groupfriendsLists);
        redisReceiver.sendToUser(userId, Result.success(iv), "init");
    }

    @Override
    public User create(String username, String sign, String avatar, String appId) {
        User user = new User();
        user.setUsername(username);
        user.setSign(sign);
        user.setAvatar(StringUtils.isEmpty(avatar) ? icon : avatar);
        user.setOnlineState(User.OnlineStateEnum.ONLINE);
        user.setAccountStatus(User.AccountStatusEnum.Normal);
        user.setApp(appService.get(appId));
        userDao.save(user);
        // 添加用户的时候默认添加分组
        userGroupService.getOrCreateDefaultGroup(user);
        return user;
    }

    @Override
    public User getOrElseThrow(Integer userId) {
        return userDao.findById(userId).orElseThrow(() -> exceptionBuilder.build(1, "用户不存在"));
    }

    @Override
    public User findById(Integer id) {
        return userDao.findById(id).orElseThrow(() -> exceptionBuilder.build(RequestEnum.USEREXIST.getMessage()));
    }

    @Override
    public User updSign(Integer userId, String sign) {
        User user = getOrElseThrow(userId);
        user.setSign(sign);
        userDao.save(user);
        originUserService.updSign(user, sign);
        sendToFollower(user, Result.of()
                .put("type", "updateSign")
                .put("sign", sign)
                .put("userid", user.getId()));
        return user;
    }

    @Override
    public User updName(Integer userId, String name) {
        User user = getOrElseThrow(userId);
        user.setUsername(name);
        userDao.save(user);
        originUserService.updName(user, name);
        sendToFollower(user, Result.of()
                .put("type", "updateSign")
                .put("sign", name)
                .put("userid", user.getId()));
        return user;
    }

    @Override
    public User updAvatar(Integer userId, String avatar) {
        User user = getOrElseThrow(userId);
        user.setAvatar(avatar);
        userDao.save(user);
        originUserService.updAvatar(user, avatar);
        sendToFollower(user, Result.of()
                .put("type", "updateSign")
                .put("avatar", avatar)
                .put("userid", user.getId()));
        return user;
    }

    @Override
    public Page<UserRecordlist> findUseridRecordCustom(Integer userId, String search) {
        Page<UserRecordlist> page = recordDao.findUseridRecordCustom(userId, search);
        page.setCountNoRead(page.getCountNoRead() + friendApplicationDao.countApplyMsg(userId));
        return page;
    }

    @Override
    public TemporaryUserinfo getTemporaryContactAndRecord(Integer userId, Integer otherId) {
        if (userId.equals(otherId)) {
            throw exceptionBuilder.build(RequestEnum.NOTSENDMINE.getCode(), RequestEnum.NOTSENDMINE.getMessage());
        }
        User other = userDao.findById(otherId).orElseThrow(() -> exceptionBuilder.build(0, RequestEnum.USEREXIST.getMessage()));
        User user = userDao.findById(userId).orElseThrow(() -> exceptionBuilder.build(0, RequestEnum.USEREXIST.getMessage()));

        TemporaryUserinfo info = new TemporaryUserinfo();
        info.setList(recordService.listUnRead(userId, otherId));
        info.setFreind(friendDao.existsByUserAndFriend(user, other));
        info.setId(other.getId());
        info.setSign(other.getSign());
        info.setStatus(other.getOnlineState().ordinal());
        info.setAvatar(other.getAvatar());
        info.setUsername(other.getUsername());
        return info;
    }

    public static final String USER_ID = "user_id";

    @Override
    public Integer getUserId(Session session) {
        Integer userId = (Integer) session.getUserProperties().get(USER_ID);
        if (userId != null) {
            return findById(userId).getId();
        } else {
            return null;
        }
    }

    @Override
    public void setUserId(Session session, Integer userId) {
        session.getUserProperties().put(USER_ID, userId);
    }

    @Override
    public String genAccessToken(User user) {
        System.out.println("genAccessToken 方法被调用了");
        return authUtil.genAccessToken(user.getId().toString(), user.getApp().getSecret());
    }

    @Override
    public User verifyAccessToken(String accessToken, App app) {
        return getOrElseThrow(Integer.parseInt(authUtil.verifyAccessToken(accessToken, app.getSecret())));
    }

    private void sendToFollower(User user, Result result) {
        send(userDao.findAllFollower(user.getId()), result);
    }

    private void send(List<User> users, Result result) {
        users.forEach(user -> redisReceiver.sendToUser(user.getId(), result.toString()));
    }
}
